package com.dede.applib.util

import java.io.BufferedReader
import java.io.DataOutputStream
import java.io.IOException
import java.io.InputStreamReader

/**
 * @author hsh
 * @time 2017/7/25 025 上午 10:11.
 * @doc
 */
object JavaShellUtil {

    var lineSeparator: String = System.getProperty("line.separator")

    var COMMAND_SH: String
    var COMMAND_EXIT = "exit\n"
    var COMMAND_LINE_END = "\n"

    private var OS_NAME: String? = null

    init {
        OS_NAME = System.getProperty("os.name")
        println(OS_NAME)
        COMMAND_SH = if (OS_NAME!!.toUpperCase().contains("WINDOWS")) {
            "cmd"
        } else {
            "sh"
        }

    }

    fun root(isRoot: Boolean) {
        COMMAND_SH = if (isRoot) "su" else "sh"
    }

    fun execCommand(command: String): CommandResult {
        return execCommand(arrayOf(command), false)
    }

    fun execCommand(command: String, isNeedResultMsg: Boolean): CommandResult {
        return execCommand(arrayOf(command), isNeedResultMsg)
    }

    fun execCommand(commands: List<String>?, isNeedResultMsg: Boolean): CommandResult {
        return execCommand(commands?.toTypedArray(), isNeedResultMsg)
    }

    fun execCommand(isNeedResultMsg: Boolean, vararg args: String): CommandResult {
        return execCommand(args.toList(), isNeedResultMsg)
    }

    /**
     * execute shell commands
     * [CommandResult.result] is -1, there maybe some excepiton.
     *
     * @param commands     command array
     * @param needResponse whether need result msg
     */
    fun execCommand(commands: Array<String>?, needResponse: Boolean): CommandResult {
        var result = -1
        if (commands == null || commands.isEmpty()) {
            return CommandResult(result, "", "空命令")
        }

        var process: Process? = null

        val successMsg = StringBuilder()
        val errorMsg = StringBuilder()

        var os: DataOutputStream? = null
        try {
            process = Runtime.getRuntime().exec(COMMAND_SH)
            os = DataOutputStream(process!!.outputStream)
            for (command in commands) {
                // donnot use os.writeBytes(commmand), avoid chinese charset error
                os.write(command.toByteArray())
                os.writeBytes(COMMAND_LINE_END)
                os.flush()
            }
            os.writeBytes(COMMAND_EXIT)
            os.flush()

            val successResult = BufferedReader(InputStreamReader(process.inputStream))
            val errorResult = BufferedReader(InputStreamReader(process.errorStream))

            if (needResponse) {
                Thread(Runnable {
                    try {
                        var s = successResult.readLine()
                        while (s != null) {
                            successMsg.append(s)
                            successMsg.append(lineSeparator)
                            s = successResult.readLine()
                        }
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }).start()
                //启动两个线程,解决process.waitFor()阻塞问题
                Thread(Runnable {
                    try {
                        var s=errorResult.readLine()
                        while (s  != null) {
                            errorMsg.append(s)
                            errorMsg.append(lineSeparator)
                            s=errorResult.readLine()
                        }
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }).start()
            }
            result = process.waitFor()
            errorResult.close()
            successResult.close()
        } catch (e: IOException) {
            e.printStackTrace()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        } finally {
            if (os != null) {
                try {
                    os.close()
                } catch (ignored: IOException) {
                }
            }
            if (process != null) {
                process.destroy()
            }
        }
        return CommandResult(result, if (successMsg.isEmpty()) "" else successMsg.deleteCharAt(successMsg.length - 1).toString(),
               if (errorMsg.isEmpty()) "" else errorMsg.deleteCharAt(errorMsg.length - 1).toString())
    }

    class CommandResult (var result: Int, var responseMsg: String, var errorMsg: String) {

        override fun toString(): String {
            return "CommandResult{" +
                    "errorMsg='" + errorMsg + '\'' +
                    ", result=" + result +
                    ", responseMsg='" + responseMsg + '\'' +
                    '}'
        }
    }
}
